---
title: Business rules
summary: Catalog of 33 business rules reachable from the ClaimBillEntry application — 13 screen-level rules plus 20 rules sourced from the consumed SAIF packages and framework.
status: draft
owner: Claims
last_reviewed: 2026-10-01
---

# Business rules

This page lists every business rule found on the execution paths of the ClaimBillEntry screens. 13 rules originate in the application's own screens, controllers and client scripts. A further 20 rules are sourced from the consumed `SAIF.SAIFCode.Core` package (contract surface and its bundled `SAIF.Services` implementation assembly), `SAIF.Framework.Common`, and `SAIF.Framework.Data.NHibernate` — reachable through service calls from ClaimBillEntry's controllers and resolved via the Legends CLI library package-context queries.

## Rule scope and coverage

| Group | Count | Note |
| --- | --- | --- |
| Application-level rules | 0 | No cross-cutting application rules were identified |
| Screen rules | 13 | Defined below |
| Package rules — `SAIF.SAIFCode.Core` contract surface (`CORE-BR-*`) | 4 | Bill status/completeness/updateability gates, defined below |
| Package rules — `SAIF.Services` implementation assembly (`SVC-BR-*`) | 11 | Server-side validation and security rules backing the service interfaces ClaimBillEntry calls, defined below |
| Package rules — `SAIF.Framework.Common` (`FWC-BR-*`) | 2 | String/boolean flag-conversion rules, defined below |
| Package rules — `SAIF.Framework.Data.NHibernate` (`NHIB-BR-*`) | 3 | Unit-of-work and repository lifecycle rules, defined below |
| Stored procedure rules | 0 | No database analysis exists for this run |
| Inherited rules | 0 | No inherited rule IDs are cataloged here; `SaifAuthorizeAttribute`'s role-based authorization behavior is now documented via the Legends CLI† in [Request pipeline and composition](operations/request-pipeline-and-composition.md), while `ClaimControllerBase.CheckSecurity` internals remain untraced beyond its call site** |
| Total | 33 | |

`SaifAuthorizeAttribute`'s role-based authorization behavior (its declared-role check, `IUserProfileService`/`ILogService`/`IEnvironmentService` requirements and its `SecurityException`-and-redirect denial path) is documented via the Legends CLI† in [Request pipeline and composition](operations/request-pipeline-and-composition.md). `ClaimControllerBase.CheckSecurity` internals beyond its call site remain untraced**; the `CORE-BR-*` and `SVC-BR-*` rules below document the status-gate and validation behavior of the bill services and validators that were reached and queried, so this is no longer a blanket "service implementations untraced" statement — see [Security and authorization](security-authorization.md) for the authorization-architecture view of these same packages.

## Rule index

| Rule | Title | Origin | Enforcement point |
| --- | --- | --- | --- |
| [BR-SCR-001](#br-scr-001-bills-must-be-in-an-openable-status) | Bills must be in an openable status | [Bill entry](../screens/entry.md) | Server and client |
| [BR-SCR-002](#br-scr-002-conflict-claim-bills-require-conflictclaim-permission) | Conflict claim bills require ConflictClaim permission | [Bill entry](../screens/entry.md) | Server |
| [BR-SCR-003](#br-scr-003-submit-requires-a-service-line) | Submit requires a service line | [Bill entry](../screens/entry.md) | Client |
| [BR-SCR-004](#br-scr-004-total-mismatch-requires-confirmation) | Total mismatch requires confirmation | [Bill entry](../screens/entry.md) | Client |
| [BR-SCR-005](#br-scr-005-status-becomes-entered-only-on-error-free-submit) | Status becomes entered only on error-free submit | [Bill entry](../screens/entry.md) | Server |
| [BR-SCR-006](#br-scr-006-discard-permission-is-enforced-client-side-only) | Discard permission is enforced client-side only | [Bill entry](../screens/entry.md) | Client |
| [BR-SCR-007](#br-scr-007-type-of-bill-must-be-numeric) | Type of bill must be numeric | [Bill entry](../screens/entry.md) | Client |
| [BR-SCR-008](#br-scr-008-admit-type-must-be-1-to-5-or-9) | Admit type must be 1 to 5 or 9 | [Bill entry](../screens/entry.md) | Client |
| [BR-SCR-009](#br-scr-009-unsaved-changes-warning) | Unsaved changes warning | [Bill entry](../screens/entry.md) | Client |
| [BR-SCR-010](#br-scr-010-procedure-type-maps-to-principal-or-other) | Procedure type maps to principal or other | [Bill entry](../screens/entry.md) | Server |
| [BR-SCR-011](#br-scr-011-inbox-owner-defaults-to-current-user) | Inbox owner defaults to current user | [Inbox](../screens/inbox.md) | Server |
| [BR-SCR-012](#br-scr-012-inbox-warns-on-confidential-claims-and-unknown-users) | Inbox warns on confidential claims and unknown users | [Inbox](../screens/inbox.md) | Server and client |
| [BR-SCR-013](#br-scr-013-search-requires-qualifying-criteria) | Search requires qualifying criteria | [Search](../screens/search.md) | Server |

## Application-level business rules

None identified. The 13 original application-local rules are all expressed on individual screens; none of them are cross-cutting at application level. The 20 package/framework rules below originate in the consumed packages, not on individual screens, and are catalogued separately in [Package and framework business rules](#package-and-framework-business-rules).

## Screen business rules

## BR-SCR-001 Bills must be in an openable status

| Field | Value |
| --- | --- |
| Statement | A bill can be opened only when its status is Pending, Entered, Audited or Suspended. |
| Trigger | A user opens a bill from the Bill entry, Inbox or Search screens. |
| Enforcement | Server in `EntryController.GetBill`; client in the Inbox and Search open handlers. |
| Outcome | Error "Only Pending, Entered, Audited, or Suspended Bills may be opened." |
| Origin | [Bill entry](../screens/entry.md) |
| Reached from | [Bill entry](../screens/entry.md), [Inbox](../screens/inbox.md), [Search](../screens/search.md); [Open a bill from the inbox](operations/open-bill-from-inbox.md); [Search bills and open a result](operations/search-and-open-bill.md) |
| Source | `ClaimBillEntry/Controllers/EntryController.cs:88-90`; `ClaimBillEntry/js/ClaimBillEntry.inbox.js:5-6`; `ClaimBillEntry/js/ClaimBillEntry.search.js:4-5` |

## BR-SCR-002 Conflict claim bills require ConflictClaim permission

| Field | Value |
| --- | --- |
| Statement | A bill on a conflict claim can be opened only by a user holding the `ConflictClaim` permission. |
| Trigger | A user opens a bill through `Entry/GetBill`. |
| Enforcement | Server: `GetClaimSecurity` reports `IsConflictClaim`, then `IsAuthorized("ConflictClaim")` is checked. |
| Outcome | Error "You are not authorized to view claim" |
| Origin | [Bill entry](../screens/entry.md) |
| Reached from | [Bill entry](../screens/entry.md); [Open a bill from the inbox](operations/open-bill-from-inbox.md) |
| Source | `ClaimBillEntry/Controllers/EntryController.cs:91-93,224-239` |

**Related package rule:** the full two-resource `ClaimSecurityService` formula this rule's `ConflictClaim` half is drawn from is defined in [SVC-BR-SEC-01](#svc-br-sec-01-conflict-and-secure-claim-access-formulas) below.

## BR-SCR-003 Submit requires a service line

| Field | Value |
| --- | --- |
| Statement | A bill cannot be submitted without at least one service line. |
| Trigger | The user selects Submit on the Bill entry screen. |
| Enforcement | Client |
| Outcome | Submit is blocked with a message |
| Origin | [Bill entry](../screens/entry.md) |
| Reached from | [Bill entry](../screens/entry.md); [Key and submit a bill](operations/key-and-submit-bill.md) |
| Source | `ClaimBillEntry/js/ClaimBillEntry.entry.js:195` |

**Related package rule:** the server-side counterpart that also enforces this requirement is defined in [SVC-BR-BILL-03](#svc-br-bill-03-bill-submit-required-fields) below.

## BR-SCR-004 Total mismatch requires confirmation

| Field | Value |
| --- | --- |
| Statement | When the Total Bill Amount differs from the Services Total, the user must confirm before the bill is submitted. |
| Trigger | The user selects Submit on the Bill entry screen. |
| Enforcement | Client |
| Outcome | Confirmation prompt; the user may proceed or cancel |
| Origin | [Bill entry](../screens/entry.md) |
| Reached from | [Bill entry](../screens/entry.md); [Key and submit a bill](operations/key-and-submit-bill.md); [Maintain diagnoses, procedures and service lines](operations/maintain-bill-lines.md) |
| Source | `ClaimBillEntry/js/ClaimBillEntry.entry.js` |

**Related package rule:** the charged-total value compared here is computed by [SVC-BR-SVCLINE-02](#svc-br-svcline-02-service-line-charged-total-and-service-type) below. Submit is also gated server-side by [SVC-BR-BILL-03](#svc-br-bill-03-bill-submit-required-fields) below, which independently requires a service line (among other fields) before submit.

## BR-SCR-005 Status becomes entered only on error-free submit

| Field | Value |
| --- | --- |
| Statement | The bill status is set to entered (`ENT`) only when the submit call returns no errors. |
| Trigger | `Entry/SubmitBill` runs. |
| Enforcement | Server: `SubmitBill` then `UpdateBillStatus` to `ENT`. |
| Outcome | Status `ENT`, or the errors are returned to the screen |
| Origin | [Bill entry](../screens/entry.md) |
| Reached from | [Bill entry](../screens/entry.md); [Key and submit a bill](operations/key-and-submit-bill.md) |
| Source | `ClaimBillEntry/Controllers/EntryController.cs:122-127` |

## BR-SCR-006 Discard permission is enforced client-side only

| Field | Value |
| --- | --- |
| Statement | The `CBEDiscardBill` permission only controls whether the Discard button is shown; `Entry/DiscardBill` does not check it. |
| Trigger | The Bill entry screen loads, and the user selects Discard. |
| Enforcement | Client: the button is hidden when `CanDiscardBill` is false. Server: none beyond the `CBPEnterBill` role. |
| Outcome | Any `CBPEnterBill` caller can set the status to discarded (`DIS`) |
| Origin | [Bill entry](../screens/entry.md) |
| Reached from | [Bill entry](../screens/entry.md); [Discard a bill](operations/discard-bill.md) |
| Source | `ClaimBillEntry/Controllers/EntryController.cs:65,159-167,209`; `ClaimBillEntry/js/ClaimBillEntry.entry.js:364-365` |

## BR-SCR-007 Type of bill must be numeric

| Field | Value |
| --- | --- |
| Statement | The Type of bill field accepts only digits, up to four characters. |
| Trigger | The user edits the field on the Bill entry screen. |
| Enforcement | Client: HTML pattern in the `_Worker` partial. |
| Outcome | "Invalid type of bill. Must be numeric." |
| Origin | [Bill entry](../screens/entry.md) |
| Reached from | [Bill entry](../screens/entry.md); [Key and submit a bill](operations/key-and-submit-bill.md) |
| Source | `ClaimBillEntry/Views/Entry/_Worker.cshtml:64-73` |

**Related package rule:** server-side field validation for this same property is defined in [SVC-BR-BILL-01](#svc-br-bill-01-bill-save-field-validation) below.

## BR-SCR-008 Admit type must be 1 to 5 or 9

| Field | Value |
| --- | --- |
| Statement | The Admit type field accepts only 1, 2, 3, 4, 5 or 9. |
| Trigger | The user edits the field on the Bill entry screen. |
| Enforcement | Client: HTML pattern in the `_Worker` partial. |
| Outcome | "Invalid Admit Type. Must be 1-5 or 9." |
| Origin | [Bill entry](../screens/entry.md) |
| Reached from | [Bill entry](../screens/entry.md); [Key and submit a bill](operations/key-and-submit-bill.md) |
| Source | `ClaimBillEntry/Views/Entry/_Worker.cshtml:76-85` |

**Related package rule:** server-side field validation for this same property is defined in [SVC-BR-BILL-01](#svc-br-bill-01-bill-save-field-validation) below.

## BR-SCR-009 Unsaved changes warning

| Field | Value |
| --- | --- |
| Statement | The browser warns the user before leaving the page with unsaved changes. |
| Trigger | The user closes or navigates away from the Bill entry screen. |
| Enforcement | Client: `beforeunload` handler. |
| Outcome | "Leaving this page before saving will cause your changes to be lost." |
| Origin | [Bill entry](../screens/entry.md) |
| Reached from | [Bill entry](../screens/entry.md); [Key and submit a bill](operations/key-and-submit-bill.md) |
| Source | `ClaimBillEntry/js/ClaimBillEntry.entry.js:2,36-47` |

## BR-SCR-010 Procedure type maps to principal or other

| Field | Value |
| --- | --- |
| Statement | A procedure with type code `P` is shown as Principal; every other type code is shown as Other. |
| Trigger | Procedures are read into the grid or a bill is loaded. |
| Enforcement | Server: AutoMapper map. |
| Outcome | Mapped procedure type in the ViewModel |
| Origin | [Bill entry](../screens/entry.md) |
| Reached from | [Bill entry](../screens/entry.md); [Maintain diagnoses, procedures and service lines](operations/maintain-bill-lines.md) |
| Source | `ClaimBillEntry/Classes/AutoMapperBootStrapper.cs:67-75` |

## BR-SCR-011 Inbox owner defaults to current user

| Field | Value |
| --- | --- |
| Statement | A blank or `SYSTEM` mail id is replaced by the current user, so the Inbox opens on the signed-in user's bills. |
| Trigger | The Inbox loads or requests its grid. |
| Enforcement | Server: `Index` uses Session `MailId` or the current user (upper-cased); `GetInboxBills` replaces `SYSTEM` or blank. |
| Outcome | Inbox of the current user |
| Origin | [Inbox](../screens/inbox.md) |
| Reached from | [Inbox](../screens/inbox.md); [Open a bill from the inbox](operations/open-bill-from-inbox.md) |
| Source | `ClaimBillEntry/Controllers/InboxController.cs:36-47,49-78` |

## BR-SCR-012 Inbox warns on confidential claims and unknown users

| Field | Value |
| --- | --- |
| Statement | The Inbox tells the user when confidential claims were filtered out of the results and when the entered user id is unknown. |
| Trigger | The Inbox grid returns data. |
| Enforcement | Server message when results are security-filtered; client message "Unknown user id." |
| Outcome | Warning text shown with the grid |
| Origin | [Inbox](../screens/inbox.md) |
| Reached from | [Inbox](../screens/inbox.md); [Open a bill from the inbox](operations/open-bill-from-inbox.md) |
| Source | `ClaimBillEntry/Controllers/InboxController.cs:63-64`; `ClaimBillEntry/js/ClaimBillEntry.inbox.js:87-99` |

## BR-SCR-013 Search requires qualifying criteria

| Field | Value |
| --- | --- |
| Statement | A search runs only when at least one of bill id, tax id, provider id, SSN, claim number or received date is supplied; status or type alone is not enough. |
| Trigger | The user submits a search. |
| Enforcement | Server: `SearchController.GetBills`. |
| Outcome | An input-error message when `ApplyValidation` is set; otherwise no query runs |
| Origin | [Search](../screens/search.md) |
| Reached from | [Search](../screens/search.md); [Search bills and open a result](operations/search-and-open-bill.md) |
| Source | `ClaimBillEntry/Controllers/SearchController.cs:62-110` |

## Package and framework business rules

20 rules are sourced from the consumed `SAIF.SAIFCode.Core` package, its bundled `SAIF.Services` implementation assembly, `SAIF.Framework.Common`, and `SAIF.Framework.Data.NHibernate`. None of the IDs below collide with [BR-SCR-001](#br-scr-001-bills-must-be-in-an-openable-status) through [BR-SCR-013](#br-scr-013-search-requires-qualifying-criteria); the screen rules above are unaffected by this section. Each rule has its own H2 definition below; the tables that open each subsection are linked navigation indexes only, not the rule's definition. Where a package rule is the server-side counterpart of a screen-level pre-check, a **Related rule** line under its H2 definition cross-references the `BR-SCR-*` entry, and a matching **Related package rule** line was added under the relevant `BR-SCR-*` entry above; the corresponding `BR-SCR-*` heading, ID, and wording are unchanged.

### SAIF.SAIFCode.Core contract surface rules

| Rule ID | Statement | Enforced by | ClaimBillEntry entry point |
| --- | --- | --- | --- |
| [CORE-BR-050](#core-br-050-bill-discard-eligibility-by-status) | Bill cannot be discarded once past an allowed status | Service-layer status gate backing discard | `EntryController.DiscardBill` |
| [CORE-BR-051](#core-br-051-bill-completeness-by-status) | A bill is complete when its status is `COM` | Service-layer completeness flag | `EntryController.GetBill`/`SaveBill` |
| [CORE-BR-052](#core-br-052-bill-updateability-by-status) | A bill is updateable when its status is `PEN`, `ENT`, `AUD`, or `SUS` | Service-layer updateability gate | `EntryController.GetBill`/`SaveBill`/`SubmitBill` |
| [CORE-BR-053](#core-br-053-bill-status-code-set) | The bill status code set is constrained to nine values | Service-layer status code validation | `EntryController` (`GetBill`, `SaveBill`, `SubmitBill`) |

---

## CORE-BR-050 Bill discard eligibility by status

| Field | Value |
| --- | --- |
| Statement | A bill cannot be discarded once past an allowed status; it is discardable when its entry source is not `E` or its status is `PEN`.† |
| Trigger | A discard request is submitted for a bill. |
| Enforcement | Service-layer status gate in the `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly), backing the bill status update. |
| Outcome | The discard status update (`DIS`) is applied only when the bill is eligible; otherwise it is rejected. |
| Origin | `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly) |
| Reached from | `EntryController.DiscardBill` → `IBillEntryService.UpdateBillStatus` (`DIS`) |
| Source | `ClaimBillEntry/Controllers/EntryController.cs:160-167` |

---

## CORE-BR-051 Bill completeness by status

| Field | Value |
| --- | --- |
| Statement | A bill is complete when its status is `COM`.† |
| Trigger | A bill is loaded or saved and its completeness flag is evaluated. |
| Enforcement | Service-layer completeness flag in the `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly). |
| Outcome | `IsBillComplete` reflects the status comparison in the returned bill. |
| Origin | `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly) |
| Reached from | `EntryController.GetBill`/`SaveBill` |
| Source | `ClaimBillEntry/Controllers/EntryController.cs:84-95,108-115` |

---

## CORE-BR-052 Bill updateability by status

| Field | Value |
| --- | --- |
| Statement | A bill is updateable when its status is `PEN`, `ENT`, `AUD`, or `SUS`.† |
| Trigger | A bill is loaded, saved, or submitted and its updateability flag is evaluated. |
| Enforcement | Service-layer updateability gate in the `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly). |
| Outcome | `IsBillUpdateable` reflects the status comparison; [BR-SCR-001](#br-scr-001-bills-must-be-in-an-openable-status) reports the error shown to the user when it is false. |
| Origin | `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly) |
| Reached from | `EntryController.GetBill`/`SaveBill`/`SubmitBill` |
| Source | `ClaimBillEntry/Controllers/EntryController.cs:84-95,108-115,118-128` |

---

## CORE-BR-053 Bill status code set

| Field | Value |
| --- | --- |
| Statement | The bill status code set is constrained to `COM`, `ENT`, `AUD`, `PEN`, `APP`, `DIS`, `EXT`, `REV`, and `SUS`.† |
| Trigger | A bill's status is read or written on any bill-entry call. |
| Enforcement | Service-layer status code validation in the `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly). |
| Outcome | Only the nine listed codes are valid status values across `GetBill`, `SaveBill`, and `SubmitBill`. |
| Origin | `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly) |
| Reached from | `EntryController` (`GetBill`, `SaveBill`, `SubmitBill`) |
| Source | `ClaimBillEntry/Controllers/EntryController.cs:84-95,108-115,118-128` |

---

### SAIF.Services implementation assembly rules

| Rule ID | Statement | Enforced by | ClaimBillEntry entry point |
| --- | --- | --- | --- |
| [SVC-BR-BILL-01](#svc-br-bill-01-bill-save-field-validation) | `BillTotalAmount`/`BillTypeCode` required; `UbBillTypeCode` numeric; `CBPAdmissionTypeCode` in accepted list | `BillValidator` | `EntryController.SaveBill` |
| [SVC-BR-BILL-02](#svc-br-bill-02-bill-save-claim-and-concurrency-validation) | Claim number must be valid; received date in range; optimistic concurrency on `UpdateNumber` mismatch | `BillValidator`/`BillEntryService` | `EntryController.SaveBill`/`SubmitBill` |
| [SVC-BR-BILL-03](#svc-br-bill-03-bill-submit-required-fields) | Submit requires claim number, billing provider (unless type `W`), and at least one service line | `BillEntryService.SubmitBill` | `EntryController.SubmitBill` |
| [SVC-BR-BILL-04](#svc-br-bill-04-new-bill-default-status-and-source) | New bill with no existing row created with status `PEN`, entry source `CBE` | `BillEntryService` | `EntryController.GetNewBill` |
| [SVC-BR-DX-01](#svc-br-dx-01-diagnosis-field-validation) | Diagnosis code/type required and valid; standard bills require a diagnosis pointer | `BillDiagnosisValidator`/`BillDiagnosisService` | `DiagnosisGridController` |
| [SVC-BR-DX-02](#svc-br-dx-02-duplicate-diagnosis-handling-by-bill-type) | Duplicate diagnosis handling varies by bill type | `BillDiagnosisService` | `DiagnosisGridController` |
| [SVC-BR-PROC-01](#svc-br-proc-01-procedure-date-and-code-validation) | Procedure date must not be in the future; code validated | `BillProcedureValidator` | `ProcedureGridController` |
| [SVC-BR-SVCLINE-01](#svc-br-svcline-01-service-line-field-validation) | Service line field-length, date, and pointer constraints | `BillServiceValidator` | `ServiceGridController` |
| [SVC-BR-SVCLINE-02](#svc-br-svcline-02-service-line-charged-total-and-service-type) | Charged total is the sum of line charges; service type derived from the service code | `BillServiceService.GetChargedServicesTotal` | `ServiceGridController` |
| [SVC-BR-PROV-01](#svc-br-prov-01-provider-lookup-validation) | Provider lookup requires TIN and a valid provider/location | Bill workflow provider validation | `ProviderController` |
| [SVC-BR-SEC-01](#svc-br-sec-01-conflict-and-secure-claim-access-formulas) | `HasConflictAccess`/`HasSecureAccess` formulas | `ClaimSecurityService` | `BaseController.CheckSecurity` (`EntryController.GetBill` performs a separate, independent local check — not a consumer of this formula) |

---

## SVC-BR-BILL-01 Bill save field validation

| Field | Value |
| --- | --- |
| Statement | `BillTotalAmount` and `BillTypeCode` are required; `UbBillTypeCode` must be numeric; `CBPAdmissionTypeCode` must be in the accepted list.† |
| Trigger | A bill is saved. |
| Enforcement | `SAIF.Services` `BillValidator`. |
| Outcome | Save fails with a validation error when any constraint is violated. |
| Origin | `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly) |
| Reached from | `EntryController.SaveBill` → `IBillEntryService.SaveBill` |
| Source | `ClaimBillEntry/Controllers/EntryController.cs:108-115` |

**Related rule:** server-enforced counterpart of the client-only [BR-SCR-007](#br-scr-007-type-of-bill-must-be-numeric) (bill type numeric) and [BR-SCR-008](#br-scr-008-admit-type-must-be-1-to-5-or-9) (admit type).

---

## SVC-BR-BILL-02 Bill save claim and concurrency validation

| Field | Value |
| --- | --- |
| Statement | The claim number must be valid, the received date must fall within the allowed range, and optimistic concurrency is enforced on an `UpdateNumber` mismatch.† |
| Trigger | A bill is saved or submitted. |
| Enforcement | `SAIF.Services` `BillValidator`/`BillEntryService`. |
| Outcome | Save or submit fails with a validation or concurrency error when a constraint is violated. |
| Origin | `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly) |
| Reached from | `EntryController.SaveBill`/`SubmitBill` |
| Source | `ClaimBillEntry/Controllers/EntryController.cs:108-115,118-128` |

**Related rule:** purely server-side; no client pre-check exists for this rule.

---

## SVC-BR-BILL-03 Bill submit required fields

| Field | Value |
| --- | --- |
| Statement | Submit requires a claim number, a billing provider unless the bill type is `W`, and at least one service line.† |
| Trigger | A bill is submitted. |
| Enforcement | `SAIF.Services` `BillEntryService.SubmitBill`. |
| Outcome | Submit fails with a validation error when a required field is missing. |
| Origin | `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly) |
| Reached from | `EntryController.SubmitBill` |
| Source | `ClaimBillEntry/Controllers/EntryController.cs:118-128` |

**Related rule:** server-enforced counterpart of [BR-SCR-003](#br-scr-003-submit-requires-a-service-line) (submit requires a service line) and [BR-SCR-004](#br-scr-004-total-mismatch-requires-confirmation) (total mismatch confirmation).

---

## SVC-BR-BILL-04 New bill default status and source

| Field | Value |
| --- | --- |
| Statement | A new bill with no existing row is created with status `PEN` and entry source `CBE`.† |
| Trigger | A new bill is requested with no matching existing bill. |
| Enforcement | `SAIF.Services` `BillEntryService`. |
| Outcome | The new bill is returned with status `PEN` and entry source `CBE`. |
| Origin | `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly) |
| Reached from | `EntryController.GetNewBill` |
| Source | `ClaimBillEntry/Controllers/EntryController.cs:99-105` |

---

## SVC-BR-DX-01 Diagnosis field validation

| Field | Value |
| --- | --- |
| Statement | `DiagnosisCode` and `DiagnosisType`/code are required and must be valid; standard bills require a diagnosis pointer.† |
| Trigger | A diagnosis row is created or updated in the diagnosis grid. |
| Enforcement | `SAIF.Services` `BillDiagnosisValidator`/`BillDiagnosisService`. |
| Outcome | The grid operation fails with a validation error when a constraint is violated. |
| Origin | `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly) |
| Reached from | `DiagnosisGridController` → `IBillDiagnosisService` |
| Source | `ClaimBillEntry/Controllers/DiagnosisGridController.cs:40-97` |

---

## SVC-BR-DX-02 Duplicate diagnosis handling by bill type

| Field | Value |
| --- | --- |
| Statement | Duplicate diagnosis handling varies by bill type: standard bills reject duplicate codes, inpatient/outpatient bills reject duplicate code+type pairs, and an unknown bill type is an error.† |
| Trigger | A diagnosis row is created or updated in the diagnosis grid. |
| Enforcement | `SAIF.Services` `BillDiagnosisService`. |
| Outcome | The grid operation fails when the applicable duplicate rule for the bill type is violated. |
| Origin | `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly) |
| Reached from | `DiagnosisGridController` |
| Source | `ClaimBillEntry/Controllers/DiagnosisGridController.cs:40-97` |

---

## SVC-BR-PROC-01 Procedure date and code validation

| Field | Value |
| --- | --- |
| Statement | A procedure date must be no later than today; the procedure code is validated by `BillProcedureValidator`.† |
| Trigger | A procedure row is created or updated in the procedure grid. |
| Enforcement | `SAIF.Services` `BillProcedureValidator`. |
| Outcome | The grid operation fails with a validation error when a constraint is violated. |
| Origin | `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly) |
| Reached from | `ProcedureGridController` → `IBillProcedureService` |
| Source | `ClaimBillEntry/Controllers/ProcedureGridController.cs:41-79` |

**Related rule:** related to, but does not back or supersede, [BR-SCR-010](#br-scr-010-procedure-type-maps-to-principal-or-other) — [BR-SCR-010](#br-scr-010-procedure-type-maps-to-principal-or-other) is a mapping rule, not a validation rule.

---

## SVC-BR-SVCLINE-01 Service line field validation

| Field | Value |
| --- | --- |
| Statement | `ProviderServiceCode` is required (≤11 chars); `SecondaryProvServiceCode` is ≤11 chars; diagnosis pointers 1-4 are ≤1 char each and unique; `ServiceDate` is ≤30 days in the future; `EndDate` is on or after the service date; `DAW` is length 1; `PrescribingProviderId` is ≤10 chars.† |
| Trigger | A service line row is created or updated in the service grid. |
| Enforcement | `SAIF.Services` `BillServiceValidator`. |
| Outcome | The grid operation fails with a validation error when a constraint is violated. |
| Origin | `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly) |
| Reached from | `ServiceGridController` → `IBillServiceService` |
| Source | `ClaimBillEntry/Controllers/ServiceGridController.cs:42-66` |

---

## SVC-BR-SVCLINE-02 Service line charged total and service type

| Field | Value |
| --- | --- |
| Statement | The charged total equals the sum of line charge amounts; the service type is derived from a non-expired CBP service code, otherwise from the NDC.† |
| Trigger | The charged total is computed for the service grid. |
| Enforcement | `SAIF.Services` `BillServiceService.GetChargedServicesTotal`. |
| Outcome | The computed total feeds the value that [BR-SCR-004](#br-scr-004-total-mismatch-requires-confirmation) compares against on submit. |
| Origin | `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly) |
| Reached from | `ServiceGridController` |
| Source | `ClaimBillEntry/Controllers/ServiceGridController.cs:122-124` |

---

## SVC-BR-PROV-01 Provider lookup validation

| Field | Value |
| --- | --- |
| Statement | Provider lookup requires a TIN; the provider must exist for that TIN; a valid provider location is required for rendering-provider lookup; the billing provider name is required for authorization items.† |
| Trigger | A provider is looked up by TIN or a billing provider is requested. |
| Enforcement | `SAIF.Services` bill workflow provider validation; no single named class is cited in the retrieved evidence. |
| Outcome | The lookup fails with a validation error when a constraint is violated. |
| Origin | `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly) |
| Reached from | `ProviderController.ValidateProviderTin`/`GetBillingProviders` → `IProviderQueryProvider`, `IBillEntryService` |
| Source | `ClaimBillEntry/Controllers/ProviderController.cs:45-56,75-79` |

---

## SVC-BR-SEC-01 Conflict and secure claim access formulas

| Field | Value |
| --- | --- |
| Statement | `HasConflictAccess = !claim.IsConflictClaim \|\| IsAuthorized(ConflictClaim)`; `HasSecureAccess = !claim.IsSecureClaim \|\| IsAuthorized(SecureClaim)`.† |
| Trigger | A user opens a bill, or the base controller evaluates claim security. |
| Enforcement | `SAIF.Services` `ClaimSecurityService`. |
| Outcome | `BaseController.CheckSecurity` proves consumption of the `HasConflictAccess` half only; `EntryController.GetBill` does not read this flag — it performs an independent local conflict-claim check instead (see Reached from). See [Security and authorization](security-authorization.md#authorization-architecture) for what is and is not proven consumed. |
| Origin | `SAIF.SAIFCode.Core` package (`SAIF.Services` assembly) |
| Reached from | `BaseController.CheckSecurity` → `access.HasConflictAccess` (`ClaimControllerBase` ctor → `IClaimSecurityService`); separately, `EntryController.GetBill` → `UserHasAccessToClaim` → `IClaimInformationService.GetClaimSecurity().IsConflictClaim` + `IsAuthorized("ConflictClaim")`, an independent local check that does not consume this computed flag |
| Source | `ClaimBillEntry/Controllers/BaseController.cs:31-34`; `ClaimBillEntry/Controllers/EntryController.cs:83-95,224-239` |

**Related rule:** this is the full two-resource source rule behind [BR-SCR-002](#br-scr-002-conflict-claim-bills-require-conflictclaim-permission), which documents the `ConflictClaim` half only; no dedicated `BR-SCR-*` screen rule currently documents the `SecureClaim` half.

---

### SAIF.Framework.Common and SAIF.Framework.Data.NHibernate rules

| Rule ID | Statement | Enforced by | ClaimBillEntry entry point |
| --- | --- | --- | --- |
| [FWC-BR-072](#fwc-br-072-string-to-boolean-conversion) | A string is truthy only for `Y`, `YES`, `TRUE`, `1`, or `ON` | `StringExtensions.ToBoolean` | Multiple controllers, `AutoMapperBootStrapper` |
| [FWC-BR-073](#fwc-br-073-boolean-to-flag-string-conversion) | Booleans render to `Y`/`N` (and other flag formats) | `BooleanExtensions.ToY_N_String` | `AutoMapperBootStrapper` |
| [NHIB-BR-001](#nhib-br-001-unit-of-work-single-active-transaction) | A unit of work cannot begin a new transaction while one is active | `NHibernateUnitOfWork.Begin()` | Every request via the dependency map |
| [NHIB-BR-002](#nhib-br-002-unit-of-work-commit-requires-begin) | A unit of work cannot be committed unless `Begin()` was called first | `NHibernateUnitOfWork.Commit()` | Same as [NHIB-BR-001](#nhib-br-001-unit-of-work-single-active-transaction) |
| [NHIB-BR-005](#nhib-br-005-repository-scoped-to-one-unit-of-work) | A `Repository<TEntity>` is scoped to exactly one unit-of-work instance | `NHibernateUnitOfWork.GetRepository<TEntity>()` | Dependency map `NHibernateUnitOfWork` named `"ClaimBillEntry"` |

---

## FWC-BR-072 String to boolean conversion

| Field | Value |
| --- | --- |
| Statement | A string is truthy only when it uppercases to one of `Y`, `YES`, `TRUE`, `1`, or `ON`; null and every other value are false.† |
| Trigger | A string flag value is converted to a boolean. |
| Enforcement | `SAIF.Framework.Common` `StringExtensions.ToBoolean`. |
| Outcome | The converted boolean is used by the calling code as a true/false flag. |
| Origin | `SAIF.Framework.Common` |
| Reached from | `{Home,Search,Entry,Provider,DiagnosisGrid,ProcedureGrid}Controller` call sites, `AutoMapperBootStrapper` |
| Source | `ClaimBillEntry/Classes/AutoMapperBootStrapper.cs:30` |

---

## FWC-BR-073 Boolean to flag string conversion

| Field | Value |
| --- | --- |
| Statement | Booleans render to `Y`/`N` (and other flag formats) depending on the conversion method chosen.† |
| Trigger | A boolean value is mapped to a flag string. |
| Enforcement | `SAIF.Framework.Common` `BooleanExtensions.ToY_N_String`. |
| Outcome | The mapped boolean property (e.g. `CompoundDrugFlag`) is rendered as a `Y`/`N` flag string for the destination DTO; this conversion is independent of any other AutoMapper mapping in `AutoMapperBootStrapper`. |
| Origin | `SAIF.Framework.Common` |
| Reached from | `AutoMapperBootStrapper` |
| Source | `ClaimBillEntry/Classes/AutoMapperBootStrapper.cs:34` |

---

## NHIB-BR-001 Unit of work single active transaction

| Field | Value |
| --- | --- |
| Statement | A unit of work cannot begin a new transaction while one is already active; doing so throws `InvalidOperationException`.† |
| Trigger | `Begin()` is called on a unit of work that already has an active transaction. |
| Enforcement | `SAIF.Framework.Data.NHibernate` `NHibernateUnitOfWork.Begin()`. |
| Outcome | `InvalidOperationException` is thrown; the transaction is not started a second time. |
| Origin | `SAIF.Framework.Data.NHibernate` |
| Reached from | Dependency map → `IUnitOfWorkFactory.ResolveNamed("oracle")`/`GetUnitOfWork` — scopes every request, including all `EntryController`/grid-controller calls |
| Source | `SAIF.DependencyMaps.Web.ClaimBillEntry/DependencyMap.cs:43,64-67` |

---

## NHIB-BR-002 Unit of work commit requires begin

| Field | Value |
| --- | --- |
| Statement | A unit of work cannot be committed unless `Begin()` was called first; doing so throws `InvalidOperationException`.† |
| Trigger | `Commit()` is called on a unit of work that was never begun. |
| Enforcement | `SAIF.Framework.Data.NHibernate` `NHibernateUnitOfWork.Commit()`. |
| Outcome | `InvalidOperationException` is thrown; the commit does not proceed. |
| Origin | `SAIF.Framework.Data.NHibernate` |
| Reached from | Same as [NHIB-BR-001](#nhib-br-001-unit-of-work-single-active-transaction) |
| Source | `SAIF.DependencyMaps.Web.ClaimBillEntry/DependencyMap.cs:43,69-72` |

**Related rule:** paired lifecycle rule to [NHIB-BR-001](#nhib-br-001-unit-of-work-single-active-transaction) — `Begin()` must precede `Commit()`, and a transaction cannot be begun twice.

---

## NHIB-BR-005 Repository scoped to one unit of work

| Field | Value |
| --- | --- |
| Statement | A `Repository<TEntity>` is scoped to exactly one `NHibernateUnitOfWork` instance for its lifetime.† |
| Trigger | A repository is resolved from a unit of work. |
| Enforcement | `SAIF.Framework.Data.NHibernate` `NHibernateUnitOfWork.GetRepository<TEntity>()`, `RepositoryBase` ctor. |
| Outcome | The repository instance is bound to the unit of work that created it and cannot be reused across unit-of-work instances. |
| Origin | `SAIF.Framework.Data.NHibernate` |
| Reached from | Dependency map `NHibernateUnitOfWork` named `"ClaimBillEntry"` (backs `ClaimBillEntryRepository`) |
| Source | `SAIF.DependencyMaps.Web.ClaimBillEntry/DependencyMap.cs:43,163-166` |

---

### Notes capability evidence gap

No dedicated `NoteService` note-validation rule was found in the recovered `SAIF.Services` evidence, beyond `NoteService` managing bill notes generally.† This is carried forward as a documented evidence gap — it is not assigned a rule ID and is not counted in the 20-rule package/framework total above.

## Rules not reachable from this application

| Origin | Item | Statement | Reason |
| --- | --- | --- | --- |
| [Inbox](../screens/inbox.md) | `InboxFilterValidator` | "Assigned to is required." | Its `InboxFilterViewModel` is not bound by any action, so the validator never runs (`ClaimBillEntry/ViewModels/Inbox/InboxFilterViewModel.cs:7,24-28`) |
| [Search](../screens/search.md) | `SearchFilterValidator` | Search filter validation | `SearchFilterViewModel` is not a compiled item, so the validator never runs |

## Rules with untraced reachability

| Origin | Item | Statement | Reachability |
| --- | --- | --- | --- |
| Transitive packages | Seven referenced SAIF packages (`SAIF.Framework.Common.Files`, `SAIF.DocumentManagement`, `SAIF.HashUtil`, `SAIF.Shared.CompareUtilities`, `SAIF.Web.API.Clients`, `LegalApi.Client`, `PdfAPI.Client`) are not consumed directly by compiled source in this repository | Not traced** | They can be reached only transitively through other packages; whether any rule in them runs for this application was not traced, so it is unknown** rather than proven unreachable |

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Operations and processes](operations-processes.md)
- [Security and authorization](security-authorization.md)
- [Data model](data-model.md)
- [Hosted endpoints](hosted-endpoints.md)
- [Tech debt](tech-debt.md)
- [Screen catalog](../screens/index.md)

> **Note:** Statements marked with `†` are derived from dependency library
> documentation via the Legends CLI. Statements marked with `*` were inferred
> from code structure or contextual evidence. Statements marked with `**` could
> not be confirmed; treat as unknown until verified.

## Sources
- ClaimBillEntry/Controllers/EntryController.cs
- ClaimBillEntry/Controllers/BaseController.cs
- ClaimBillEntry/Controllers/InboxController.cs
- ClaimBillEntry/Controllers/SearchController.cs
- ClaimBillEntry/Controllers/DiagnosisGridController.cs
- ClaimBillEntry/Controllers/ProcedureGridController.cs
- ClaimBillEntry/Controllers/ServiceGridController.cs
- ClaimBillEntry/Controllers/ProviderController.cs
- ClaimBillEntry/Classes/AutoMapperBootStrapper.cs
- ClaimBillEntry/Views/Entry/_Worker.cshtml
- ClaimBillEntry/js/ClaimBillEntry.entry.js
- ClaimBillEntry/js/ClaimBillEntry.inbox.js
- ClaimBillEntry/js/ClaimBillEntry.search.js
- ClaimBillEntry/ViewModels/Inbox/InboxFilterViewModel.cs
- SAIF.DependencyMaps.Web.ClaimBillEntry/DependencyMap.cs
